
#include "include.h"


volatile Can_Rx_MsgType Can_RxFIFOArray[CAN_RX_FIFOLength]={0};
volatile u32 u32Can_RxFIFOFrontIndex = 0u;
volatile u32 u32Can_RxFIFORearIndex = 0u;
CanRxMsg RxMsg;
Can_Rx_MsgType ReadMsg = {0};
Msg_InfoType Msg_Info;

CAN_BUSOFFInfoType CAN_BUSOFFInfo;

CanTxMsg Can_TxFIFOArray[CAN_TX_FIFOLength] ={0};
u32 u32Can_TxFIFOFrontIndex = 0u;
u32 u32Can_TxFIFORearIndex = 0u;
u32 u32Can_TxMsgCnt=0u;
u32 u32Can_TxTimeStamp=0u;

typedef struct
{
	u8 u8SignalBitStart;
	u8 u8SignalBitLength;
	u32 u32Can_SignalMsgId;
}CanMsg_SignalInfoType;

const CanMsg_SignalInfoType Can_SignalInfo[Msg_MaxSignal] =
{
	{CAN_UCPControlSignalStartBit,CAN_UCPControlSignalLength,CAN_UCPControlSignalCanID},
};


void USB_LP_CAN1_RX0_IRQHandler(void)
{
	u8 u8SiftCnt=0,u8DataCnt=0;
	CAN_Receive(CAN1,CAN_FIFO0,&RxMsg);
	if(RxMsg.IDE == CAN_Id_Standard)
	{
		for(u8SiftCnt=0;u8SiftCnt<CANID_Number;u8SiftCnt++)
		{
			if(RxMsg.StdId == u32CanId_Array[u8SiftCnt])
			{
				break;
			}else{;}
		}
		if(u8SiftCnt>=CANID_Number)
		{
			;
		}
		else
		{
			Can_RxFIFOArray[u32Can_RxFIFORearIndex].u32Rx_MsgId = (u32)(RxMsg.StdId);
			Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Ide = RxMsg.IDE;
			Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Dlc = RxMsg.DLC;
			for(u8DataCnt=0;u8DataCnt<Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Dlc;u8DataCnt++)
			{
				Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Data[u8DataCnt] = RxMsg.Data[u8DataCnt];
			}
			u32Can_RxFIFORearIndex++;
			if(u32Can_RxFIFORearIndex>=CAN_RX_FIFOLength)
			{
				u32Can_RxFIFORearIndex=0;
			}else{;}
		}
	}
	else
	{
		for(u8SiftCnt=0;u8SiftCnt<CANID_Number;u8SiftCnt++)
		{
			if(RxMsg.ExtId == u32CanId_Array[u8SiftCnt])
			{
				break;
			}else{;}
		}
		if(u8SiftCnt>=CANID_Number)
		{
			;
		}
		else
		{
			Can_RxFIFOArray[u32Can_RxFIFORearIndex].u32Rx_MsgId = (u32)(RxMsg.ExtId);
			Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Ide = RxMsg.IDE;
			Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Dlc = RxMsg.DLC;
			for(u8DataCnt=0;u8DataCnt<Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Dlc;u8DataCnt++)
			{
				Can_RxFIFOArray[u32Can_RxFIFORearIndex].u8Rx_Data[u8DataCnt] = RxMsg.Data[u8DataCnt];
			}
			u32Can_RxFIFORearIndex++;
			if(u32Can_RxFIFORearIndex>=CAN_RX_FIFOLength)
			{
				u32Can_RxFIFORearIndex=0;
			}else{;}
		}
	}
}

static u32 Can_GetDataFromFormat(u8 u8BitStart,u8 u8BitLength,u8 u8format,Can_Rx_MsgType*Read_Msg)
{
	u8 u8Length  = (u8)(u8BitLength);
	u8 u8Byte    = (u8)(u8BitStart>>3);
	u8 u8ByteBit = (u8)(u8BitStart&0x07);
	u8 u8ByteLength = (u8)(8-u8ByteBit);
	u32 u32Data = 0u;
	
	while(u8Length>0)
	{
		u32Data += ((u32)(Read_Msg->u8Rx_Data[u8Byte]>>u8ByteBit)<<(u8BitLength-u8Length));
		u8Length = (u8Length>u8ByteLength)?(u8Length-u8ByteLength):0;
		if(u8Length>0)
		{
			u8Byte = (0==u8format)?(u8Byte+1):(u8Byte-1);
			u8ByteBit = 0;
			u8ByteLength = 8;
		}
	}
	u32Data &= (u32)(((u32)0x01<<u8BitLength)-1);
	return u32Data;
}

static bool Can_APPReadMsgFunction(Can_Rx_MsgType* RxMsg)
{
	u8 cnt=0u,u8format=0;
	u8format = CAN_SignalFormat;
	for(cnt=0;cnt<Msg_MaxSignal;cnt++)
	{
		if(RxMsg->u32Rx_MsgId == Can_SignalInfo[cnt].u32Can_SignalMsgId)
		{
			Msg_Info.u16SignalFlag = (u16)(1<<cnt);
			Msg_Info.u32SignalValue[cnt] = (u32)(Can_GetDataFromFormat(Can_SignalInfo[cnt].u8SignalBitStart,
			                          Can_SignalInfo[cnt].u8SignalBitLength,u8format,&ReadMsg));
			Msg_Info.u32TimeStampCnt[cnt] = u32TimBaseCnt;
		}
		else
		{
			Msg_Info.u16SignalFlag &=  (u16)(Msg_Info.u16SignalFlag)^(1<<cnt);
		}
	}
	return TRUE;
}


static bool CANIF_ReadMsg(Can_Rx_MsgType*sReadMsg)
{
	bool ReadResult = FALSE;
	Can_Rx_MsgType* GetMsg = (Can_Rx_MsgType*)&Can_RxFIFOArray[u32Can_RxFIFOFrontIndex];
	if(u32Can_RxFIFOFrontIndex != u32Can_RxFIFORearIndex)
	{
		sReadMsg->u32Rx_MsgId = GetMsg->u32Rx_MsgId;
		sReadMsg->u8Rx_Ide = GetMsg->u8Rx_Ide;
		sReadMsg->u8Rx_Dlc = GetMsg->u8Rx_Dlc;
		for(u8 cnt=0;cnt < GetMsg->u8Rx_Dlc; cnt++)
		{
			sReadMsg->u8Rx_Data[cnt] = GetMsg->u8Rx_Data[cnt];
		}
		ReadResult = TRUE;
		u32Can_RxFIFOFrontIndex++;
		if(u32Can_RxFIFOFrontIndex>=CAN_RX_FIFOLength)
		{
			u32Can_RxFIFOFrontIndex=0;
		}else{;}
	}else{;}
	return ReadResult;
}

static void Can_MessageReadMainFunction(void)
{
	bool ReadMsgFlag = TRUE;
	ReadMsgFlag = CANIF_ReadMsg(&ReadMsg);
	if(FALSE == ReadMsgFlag)
	{
		return;
	}
	else
	{
		Can_APPReadMsgFunction(&ReadMsg);
	}
}



//static void Can_MemoryTXFIFO(u8* FillArea,const u8* WantFillArea,u16 Size)
//{
//	u16 u16Cnt=0;
//	for(u16Cnt=0;u16Cnt<Size;u16Cnt++)
//	{
//		FillArea[u16Cnt] = WantFillArea[u16Cnt];
//	}
//}


static void CANIF_Transmit(CanTxMsg*TxMsg)
{
  if(u32Can_TxMsgCnt<CAN_TX_FIFOLength)
	{
		Can_TxFIFOArray[u32Can_TxFIFORearIndex] = *TxMsg;
		
//		Can_MemoryTXFIFO((u8*)&Can_TxFIFOArray[u32Can_TxFIFORearIndex],(const u8*)TxMsg,sizeof(CanTxMsg));
		
		u32Can_TxFIFORearIndex++;
		if(u32Can_TxFIFORearIndex>=CAN_TX_FIFOLength)
		{
			u32Can_TxFIFORearIndex = 0;
		}
		u32Can_TxMsgCnt++;
	}
}
static void Can_MessageWriteMainFunction(void)
{
	CanTxMsg TxMessage;
	
	if(((u32TimBaseCnt-u32Can_TxTimeStamp>=CAN_APTDTxMsgCycle)||(CAN_BUSOFFInfo.u8AllowTranSmitFlag ==1))
		 &&(CAN_TSR_TME0 == (CAN1->TSR&CAN_TSR_TME0)))
	{
		CAN_BUSOFFInfo.u8AllowTranSmitFlag = 0;
		TxMessage.StdId = CAN_APTDSignalCanID;
		TxMessage.IDE = CAN_FRAMETYPE;
		TxMessage.RTR = 0;
		TxMessage.DLC = 8;
		TxMessage.Data[0] = (u8)(100>>4);
		TxMessage.Data[1] = (u8)(((100&0x0F)<<4)|(50>>3));
		TxMessage.Data[2] = (u8)((50&0x07)<<5);
		TxMessage.Data[3] = 0x00;
		TxMessage.Data[4] = (u8)(150);
		TxMessage.Data[5] = 0x55;
		TxMessage.Data[6] = (u8)((2<<6)|(5000>>8));
		TxMessage.Data[7] = (u8)(5000&0xFF);
		CANIF_Transmit(&TxMessage);
		u32Can_TxTimeStamp = u32TimBaseCnt;
	}
}

static void CanIf_WriteMainFunction(void)
{
	CanTxMsg* msg = &Can_TxFIFOArray[u32Can_TxFIFOFrontIndex];
	if((u32Can_TxMsgCnt>0)&&(CAN_TSR_TME0 == (CAN1->TSR&CAN_TSR_TME0)))
	{
		CAN_Transmit(CAN1,msg);
		u32Can_TxFIFOFrontIndex++;
		if(u32Can_TxFIFOFrontIndex>=CAN_TX_FIFOLength)
		{
			u32Can_TxFIFOFrontIndex=0;
		}
		u32Can_TxMsgCnt--;
	}
}

void Can_BusoffTimeCnt(void)
{
	if(CAN_BUSOFFInfo.u16Busoff_ResetTime>0)
	{
		CAN_BUSOFFInfo.u16Busoff_ResetTime--;
	}
}

static void Can_RrtryTranSmit(void)
{
	if(0 == u32Can_TxFIFOFrontIndex)
	{
		u32Can_TxMsgCnt++;
		u32Can_TxFIFOFrontIndex = (CAN_TX_FIFOLength-1);
	}
	else
	{
		u32Can_TxMsgCnt++;
		u32Can_TxFIFOFrontIndex--;
	}
}



static void Can_BusoffFunction(void)
{
	FlagStatus bRes = RESET;
	
	bRes = CAN_GetFlagStatus(CAN1,CAN_FLAG_BOF);
	
	switch(CAN_BUSOFFInfo.CAN_BUSOFFStatus)
	{
		case BUSOFF_NormalRunning:
			if(bRes==SET)
			{
				if(CAN_BUSOFFInfo.u8Busoff_ResetCnt<=10)
				{
					CAN_BUSOFFInfo.CAN_BUSOFFStatus = BUSOFF_FastBUSOFF;
					CAN_BUSOFFInfo.u16Busoff_ResetTime = 100;
				}
				else
				{
					CAN_BUSOFFInfo.CAN_BUSOFFStatus = BUSOFF_SlowBUSOFF;
				  CAN_BUSOFFInfo.u16Busoff_ResetTime = 1000;
				}
				if(CAN_BUSOFFInfo.u8Busoff_ResetCnt<0xFF)
				{
					CAN_BUSOFFInfo.u8Busoff_ResetCnt++;
				}
			}
			else
			{
				if(CAN_TSR_TXOK0==(CAN1->TSR&CAN_TSR_TXOK0))
				{
					CAN_BUSOFFInfo.u8LastTranSmitFlag = 1;
				}
				else
				{
					CAN_BUSOFFInfo.u8LastTranSmitFlag = 0;
				}
				if( 1 == CAN_BUSOFFInfo.u8LastTranSmitFlag )
				{
					CAN_BUSOFFInfo.u8Busoff_ResetCnt=0;
				}
			}
			break;
		case BUSOFF_FastBUSOFF:
			if(0==CAN_BUSOFFInfo.u16Busoff_ResetTime)
			{
				CAN_BUSOFFInfo.CAN_BUSOFFStatus = BUSOFF_Recovery;
			}
			break;
		case BUSOFF_Recovery:
			Can_RrtryTranSmit();
			CAN_DeInit(CAN1);
		  CAN_OperatingModeRequest(CAN1,CAN_OperatingMode_Initialization);
		  Can_Config();
		  CAN_OperatingModeRequest(CAN1,CAN_OperatingMode_Normal);
		  CAN_BUSOFFInfo.u32Busoff_ResetTimeStamp = u32TimBaseCnt;
		  CAN_BUSOFFInfo.u8AllowTranSmitFlag = 1;
		  CAN_BUSOFFInfo.CAN_BUSOFFStatus = BUSOFF_NormalRunning;
			break;
		case BUSOFF_SlowBUSOFF:
			if(0==CAN_BUSOFFInfo.u16Busoff_ResetTime)
			{
				CAN_BUSOFFInfo.CAN_BUSOFFStatus = BUSOFF_Recovery;
			}
			break;
		default :
			break;
	}
}



void CANIF_MainFunction(void)
{
	Can_BusoffFunction();
	Can_MessageReadMainFunction();
	Can_MessageWriteMainFunction();
  CanIf_WriteMainFunction();
}


